package com.easy.api.aop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.easy.api.bean.decrypt.EncryptionBean;
import com.easy.api.utils.ApplicationContextUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author liuyuan
 */
@Component
@Aspect
public class ApiDecryptAspect {

    private final String decryptName = "encryptionBean";

    @Pointcut("@annotation(com.easy.api.annotation.ApiDecrypt)")
    public void point() {
    }

    @Before("point()")
    public void doBefore(JoinPoint joinPoint) {

    }


    @Around("point()")
    public Object doSetFiledValue(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        ApplicationContext applicationContext = ApplicationContextUtils.getApplicationContext();
        EncryptionBean encryptionBean = applicationContext.getBean(decryptName, EncryptionBean.class);
        Object[] args = joinPoint.getArgs();
        if(encryptionBean.isOpen()){
            String requestParam = encryptionBean.getRequestParam();
            String param = request.getParameter(requestParam);
            String decrypt = encryptionBean.getDecrypt();
            String key = encryptionBean.getKey();
            Class<?> classBean = encryptionBean.getClassBean();

            Method[] methods = classBean.getMethods();
            Method useMethod = null;
            for (Method method:methods) {
                if(decrypt.equals(method.getName())){
                    useMethod = method;
                    break;
                }
            }
            // Object invoke = useMethod.invoke(paramArgs);
            Object invoke = useMethod.invoke(classBean, param, key);
            Map<String, Object> params = JSONObject.parseObject(invoke.toString(), new TypeReference<Map<String, Object>>(){});
            MethodSignature signature = (MethodSignature)joinPoint.getSignature();
            Class[] parameterTypes = signature.getParameterTypes();
            String[] parameterNames = signature.getParameterNames();
            for (int i= 0; i<parameterTypes.length;i++){
                String typeName = parameterTypes[i].getTypeName();
                if(ParamType.String.getDesc().equals(typeName)){
                    args[i] = params.get(parameterNames[i]);
                }else if(ParamType.Integer.getDesc().equals(typeName)){
                    args[i] = params.get(parameterNames[i]);
                }else if(ParamType.Map.getDesc().equals(typeName)){
                    args[i] = params.get(parameterNames[i]);
                }else {
                    Class<?> aClass = args[i].getClass();
                    Map<String, Object> map = (Map<String, Object>) params.get(parameterNames[i]);
                    String json1= JSON.toJSONString(map);
                    Object o = JSONObject.parseObject(json1, aClass);
                    args[i] = o;
                }
            }
        }
        Object proceed = joinPoint.proceed(args);
        return proceed;
    }

}
